
#include <bits/stdc++.h>
using namespace std;

const int MOD = 1000000007;
map<pair<int, int>, int> mp;

long long a[300005]; // a[i]表示第i组平行线的数量

int main() {
  int n;
  cin >> n;
  for (int i = 1; i <= n; i++) {
    int a, b, c;
    cin >> a >> b >> c;
    // 约分a，b
    if (a == 0) {
      mp[{0, 1}]++;
    } else if (b == 0) {
      mp[{1, 0}]++;
    } else {
      if (a < 0) {
        a = -a;
        b = -b;
      }
      int d = __gcd(a, b);
      mp[{a / d, b / d}]++;
    }
  }
  long long ans = 0;
  long long sum = 0; // 没有平行线的直线数量
  int total = 0;     // 平行线组数
  for (auto it = mp.begin(); it != mp.end(); it++) {
    if (it->second == 1) {
      sum++; // 统计没有平行线的直线数量
    } else {
      total++;               // 统计有平行线的组数
      a[total] = it->second; // 记录每组平行线的数量
    }
  }

  // 没有平行线组成的三角形个数
  ans = sum * (sum - 1) * (sum - 2) / 6;
  ans %= MOD;
  // 有一组平行线和两个没有平行线直线组成的三角形个数
  for (int i = 1; i <= total; i++) {
    ans += a[i] * sum * (sum - 1) / 2;
    ans %= MOD;
  }
  // 由两组平行线和一个没有平行线直线组成的三角形个数
  for (int i = 1; i <= total; i++) {
    for (int j = i + 1; j <= total; j++) {
      ans += a[i] * a[j] * sum;
      ans %= MOD;
    }
  }
  // 由三组平行线组成的三角形的个数
  for (int i = 1; i <= total; i++) {
    for (int j = i + 1; j <= total; j++) {
      for (int k = j + 1; k <= total; k++) {
        ans += a[i] * a[j] * a[k];
        ans %= MOD;
      }
    }
  }
  cout << ans;
  return 0;
}